home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
xvisrc.zip
/
FILEIO.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
15KB
|
648 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)fileio.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
fileio.c
* module function:
File i/o routines.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
#ifdef MEGAMAX
overlay "fileio"
#endif
/*
* Definition of a text file format.
*
* This structure may need additional entries to cope with very strange file
* formats (such as VMS).
*/
struct tfformat
{
int tf_eolnchars[2]; /* end of line markers */
int tf_eofchar; /* end of file marker */
unsigned char tf_dynamic; /* autodetect format? */
};
/*
* Names of values for the P_format enumerated parameter.
*
* It is essential that these are in the same order as the fmt_...
* symbolic constants defined in xvi.h.
*/
char *fmt_strings[] = {
"cstring",
"macintosh",
"msdos",
"os2",
"qnx",
"tos",
"unix",
NULL,
};
/*
* Format structures.
*
* It is essential that these are in the same order as the fmt_...
* symbolic constants defined in xvi.h.
*
* We don't use '\r' or '\n' to define the end-of-line characters
* because some compilers interpret them differently & this code has
* to work the same on all systems.
*/
#define NOCHAR EOF
static const struct tfformat tftable [] = {
{ { '\0', NOCHAR }, EOF, FALSE }, /* fmt_CSTRING */
{ { CTRL('M'), NOCHAR }, EOF, FALSE }, /* fmt_MACINTOSH */
{ { CTRL('M'), CTRL('J') }, CTRL('Z'), TRUE }, /* fmt_MSDOS */
{ { CTRL('M'), CTRL('J') }, CTRL('Z'), TRUE }, /* fmt_OS2 */
{ { '\036', NOCHAR }, EOF, FALSE }, /* fmt_QNX */
{ { CTRL('M'), CTRL('J') }, EOF, TRUE }, /* fmt_TOS */
{ { CTRL('J'), NOCHAR }, EOF, FALSE } /* fmt_UNIX */
};
/*
* Index of last entry in tftable.
*/
#define TFMAX (sizeof tftable / sizeof (struct tfformat) - 1)
/*
* Current text file format.
*/
static struct tfformat curfmt = { { 0, 0 }, 0, FALSE };
#define eolnchars curfmt.tf_eolnchars
#define eofchar curfmt.tf_eofchar
/*
* Name of current text file format.
*/
static char *fmtname = "INTERNAL ERROR";
/*
* Copy the tftable entry indexed by tfindex into curfmt & update
* fmtname. Return FALSE if the parameter is invalid, otherwise TRUE.
*
* This is called from set_format() (below).
*
* Note that we copy a whole tfformat structure here, instead of just copying
* a pointer. This is so that curfmt.eolnchars & curfmt.eofchar will compile
* to absolute address references instead of indirections, which should be
* significantly more efficient because they are referenced for every
* character we read or write.
*/
static bool_t
txtformset(tfindex)
int tfindex;
{
if (tfindex < 0 || tfindex > TFMAX)
return FALSE;
(void) memcpy((char *) &curfmt, (const char *) &tftable[tfindex],
sizeof curfmt);
fmtname = fmt_strings[tfindex];
return TRUE;
}
/*
* Check value of P_format parameter.
*/
bool_t
set_format(window, new_value, interactive)
Xviwin *window;
Paramval new_value;
bool_t interactive;
{
if (!txtformset(new_value.pv_i)) {
if (interactive) {
show_error(window, "Invalid text file format (%d)",
new_value.pv_i);
}
return(FALSE);
}
return(TRUE);
}
/*
* Find out if there's a format we know about with the single specified
* end-of-line character. If so, change to it.
*/
static bool_t
eolnhack(c)
register int c;
{
register int tfindex;
for (tfindex = 0; tfindex <= TFMAX; tfindex++) {
register const int *eolp;
eolp = tftable[tfindex].tf_eolnchars;
if (eolp[0] == c && eolp[1] == NOCHAR) {
(void) txtformset(tfindex);
set_param(P_format, tfindex, (char **) NULL);
P_setchanged(P_format);
return TRUE;
}
}
return FALSE;
}
/*
* Read in the given file, filling in the given "head" and "tail"
* arguments with pointers to the first and last elements of the
* linked list of Lines; if nothing was read, both pointers are set to
* NULL. The return value is the number of lines read, if successful
* (this can be 0 for an empty file), or an error return code, which
* can be gf_NEWFILE, gf_CANTOPEN, gf_IOERR or gf_NOMEM.
*
* If there is an error, such as not being able to read the file or
* running out of memory, an error message is printed; otherwise, a
* statistics line is printed using show_message().
*
* The "extra_str" string is printed just after the filename in the
* displayed line, and is typically used for "Read Only" messages. If
* the file doesn't appear to exist, the filename is printed again,
* immediately followed by the "no_file_str" string, & we return
* gf_NEWFILE.
*/
long
get_file(window, filename, headp, tailp, extra_str, no_file_str)
Xviwin *window;
char *filename;
Line **headp;
Line **tailp;
char *extra_str;
char *no_file_str;
{
register FILE *fp; /* ptr to open file */
#ifndef i386
register
#endif
unsigned long nchars; /* number of chars read */
unsigned long nlines; /* number of lines read */
unsigned long nulls; /* number of null chars */
unsigned long toolong; /*
* number of lines
* which were too long
*/
bool_t incomplete; /* incomplete last line */
Line *lptr = NULL; /* pointer to list of lines */
Line *last = NULL; /*
* last complete line
* read in
*/
Line *lp; /*
* line currently
* being read in
*/
register enum {
at_soln,
in_line,
got_eolnc0,
at_eoln,
at_eof
} state;
register char *buff; /*
* text of line
* being read in
*/
register int col; /* current column in line */
if (P_ischanged(P_format)) {
show_message(window, "\"%s\" [%s]%s", filename, fmtname, extra_str);
} else {
show_message(window, "\"%s\"%s", filename, extra_str);
}
fp = fopenrb(filename);
if (fp == NULL) {
*headp = *tailp = NULL;
if (exists(filename)) {
show_error(window, "Can't read \"%s\"", filename);
return(gf_CANTOPEN);
} else {
show_message(window, "\"%s\"%s", filename, no_file_str);
return(gf_NEWFILE);
}
}
#ifdef SETVBUF_AVAIL
{
unsigned int bufsize;
bufsize = READBUFSIZ;
/*
* Keep trying to set the buffer size to something
* large, reducing the size by 1/2 each time.
* This will eventually work, and will not usually
* take very many calls. (jmd)
*/
while (setvbuf(fp, (char *) NULL, _IOFBF, bufsize) != 0 &&
bufsize > 1) {
bufsize /= 2;
}
}
#endif /* SETVBUF_AVAIL */
nchars = nlines = nulls = toolong = 0;
col = 0;
incomplete = FALSE;
state = at_soln;
while (state != at_eof) {
register int c;
c = getc(fp);
if (c == EOF || c == eofchar) {
if (state != at_soln) {
/*
* Reached EOF in the middle of a line; what
* we do here is to pretend we got a properly
* terminated line, and assume that a
* subsequent getc will still return EOF.
*/
incomplete = TRUE;
state = at_eoln;
} else {
state = at_eof;
break;
}
} else {
nchars++;
switch (state) {
case at_soln:
/*
* We're at the start of a line, &
* we've got at least one character,
* so we have to allocate a new Line
* structure.
*
* If we can't do it, we throw away
* the lines we've read in so far, &
* return gf_NOMEM.
*/
if ((lp = newline(MAX_LINE_LENGTH)) == NULL) {
if (lptr != NULL) {
throw(lptr);
}
(void) fclose(fp);
*headp = *tailp = NULL;
return(gf_NOMEM);
} else {
buff = lp->l_text;
}
case in_line:
if (c == eolnchars[0]) {
if (eolnchars[1] == NOCHAR) {
state = at_eoln;
} else {
state = got_eolnc0;
continue;
}
} else if (c == eolnchars [1] && curfmt.tf_dynamic &&
eolnhack(c)) {
/*
* If we get the second end-of-line
* marker, but not the first, see if
* we can accept th